package com.young.modbus.service;


import com.serotonin.modbus4j.ModbusMaster;
import com.serotonin.modbus4j.exception.ModbusTransportException;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersRequest;
import com.serotonin.modbus4j.msg.ReadHoldingRegistersResponse;
import com.young.modbus.config.PlcConfig;
import com.young.modbus.config.PlcPoints;
import com.young.modbus.domain.PlcStatus;
import com.young.modbus.utils.Modbus4jWriteUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

/**
 * @className: ModbusService
 * @author: Young
 * @date: 2024/12/29 23:01
 * @Version: 1.0
 * @description:
 */
@Slf4j
@Service
public class ModbusService {

    @Autowired
    private ModbusMaster modbusMaster;

    @Autowired
    private PlcConfig config;

    @Autowired
    private PlcPoints points;

    private short[] positionSignal = new short[3];

    private static short[] heart = {3};

    private boolean productArrived = false;
    private boolean scanAllowed = false;
    private boolean startTesting = false;

    private final PlcStatus status;

    @Autowired
    public ModbusService(PlcStatus status) {
        this.status = status;
    }

    /**
     * 每隔1s读一次到位信号和允许扫码信号
     */
    @Scheduled(fixedRate = 1000)
    public void signal() {
        try {
            ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(config.getSlaveId(), points.getPositionSignal(), 3);
            ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) modbusMaster.send(request);
            if (response.isException()) {
                log.error("读取PLC信号数据出错: {}",response.getExceptionMessage());
            }else{
                positionSignal = response.getShortData();
                status.setPositionSignal(positionSignal[0]);
                status.setAllowScan(positionSignal[1]);
                if (!productArrived && (positionSignal[0]==1)){
                    log.info("PLC---产品到位---- √");
                    productArrived = true;
                    //todo 执行产品到位相关操作
                } else if (productArrived && !scanAllowed && (positionSignal[1]==1)) {
                    log.info("PLC--允许扫码---- √");
                    scanAllowed = true;
                    //todo 执行允许扫码相关操作
                } else if (productArrived && !startTesting && (positionSignal[2]==1)) {
                    log.info("PLC--开始测试---- √");
                    startTesting = true;
                    //todo 执行开始测试相关操作
                }
            }
        } catch (ModbusTransportException e) {
            log.error("signal定时任务读取数据出错！{}",e.getMessage());
        }
    }

    /**
     * 2s读一次心跳
     */
    @Scheduled(fixedRate = 2000)
    public void heart() {
        try {
            ReadHoldingRegistersRequest request = new ReadHoldingRegistersRequest(config.getSlaveId(), points.getHeart(), 1);
            ReadHoldingRegistersResponse response = (ReadHoldingRegistersResponse) modbusMaster.send(request);
            if (response.isException()) {
                log.error("读取PLC心跳数据出错: {}",response.getExceptionMessage());
            }else{
                if (heart[0]!=response.getShortData()[0]){
                    heart[0]=response.getShortData()[0];
                }else {
                    log.warn("读取PLC心跳值一致，设备可能离线！");
                }
            }
        } catch (ModbusTransportException e) {
            log.error("heart定时任务读取数据出错！{}",e.getMessage());
        }
    }
    /**
     * 写入PLC  扫码结果
     * @param val (1：OK、2：NG)
     * @return
     */
    public boolean writeScanRes(short val){
        try {
            boolean res = Modbus4jWriteUtils.writeRegister(modbusMaster,config.getSlaveId(),100,val);
            if (res){
                status.setScanResult(val);
            }
            return res;
        } catch (Exception e) {
            log.error("写入扫码结果出错! {}",e.getMessage());
        }
        return false;
    }

    /**
     * 写入测试结果
     * @param val (1：OK、2：NG)
     * @return
     */
    public boolean writeTestRes(short val){
        try {
            boolean res = Modbus4jWriteUtils.writeRegister(modbusMaster,config.getSlaveId(),101,val);
            if (res){
                status.setTestResult(val);
            }
            resetState();
            return res;
        } catch (Exception e) {
            log.error("写入测试结果出错! {}",e.getMessage());
        }
        return false;
    }

    /**
     * 写入允许放行
     * @param val (1：OK、0：初始值)
     * @return
     */
    public boolean writeAllowPass(short val){
        try {
            return Modbus4jWriteUtils.writeRegister(modbusMaster,config.getSlaveId(),102,val);
        } catch (Exception e) {
            log.error("写入放行结果出错! {}",e.getMessage());
        }
        return false;
    }

    /**
     * 重置所有状态
     */
    private void resetState() {
        productArrived = false;
        scanAllowed = false;
        startTesting = false;
        log.info("状态重置，进入下一回合");
    }

}
